package org.aplikator.client.local.widgets; import java.util.Date; import org.aplikator.client.local.Aplikator; import org.aplikator.client.shared.data.PrimaryKey; import org.aplikator.client.shared.descriptor.PropertyDTO; import org.gwtbootstrap3.client.ui.*; import org.gwtbootstrap3.client.ui.base.form.AbstractForm; import com.google.gwt.core.client.GWT; import com.google.gwt.dom.client.FormElement; import com.google.gwt.dom.client.Style; import com.google.gwt.event.dom.client.*; import com.google.gwt.event.logical.shared.ValueChangeEvent; import com.google.gwt.event.logical.shared.ValueChangeHandler; import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiField; import com.google.gwt.uibinder.client.UiHandler; import com.google.gwt.user.client.Command; import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Event; import com.google.gwt.user.client.Timer; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.DeckPanel; import com.google.gwt.user.client.ui.FileUpload; import com.google.gwt.user.client.ui.FormPanel; import com.google.gwt.user.client.ui.HTML; import com.google.gwt.user.client.ui.ScrollPanel; import com.google.gwt.xml.client.Document; import com.google.gwt.xml.client.Node; import com.google.gwt.xml.client.XMLParser; public class BinaryFieldWidget extends Composite implements DataField<String> { public static final String BUTTON_WIDTH = "90px"; public static final String ENTITY_ID = "entityId"; public static final String PROPERTY_ID = "propertyId"; public static final String PRIMARY_KEY_ID = "primaryKey"; public static final String MAXSIZE_ID = "maxSize"; public static final String ATTACHMENT_ID = "attachment"; public static final String ERROR_PREFIX = "XXXERRORXXX"; public static final int FULL_SIZE_ATTACHMENT_CODE = 0; public static final int THUMBNAIL_SIZE_CODE = -1; public static final int PREVIEW_SIZE_CODE = -2; public static final int FULL_SIZE_IMAGE_CODE = -3; private static BinaryFieldWidgetUiBinder uiBinder = GWT.create(BinaryFieldWidgetUiBinder.class); @UiField Column wrapper; @UiField FormLabel label; @UiField NavbarText labelHolder; @UiField Button buttonUpload; @UiField AnchorButton buttonDownload; @UiField DeckPanel thumbnailHolder; @UiField Image thumbnail; FormControlStatic primaryKeyField; private FileUpload upload; private ProgressTimer timer; private HTML statusLabel = new HTML(" "); private boolean uploading = false; private Modal uploadDialog; private String entityId; private PropertyDTO property; private PrimaryKey primaryKey; private String tempFileId; private boolean dirty = false; private boolean useThumbnail = true; private boolean enabled = true; public BinaryFieldWidget(PropertyDTO property, String localizedName, String entityId, int size, boolean enabled, int height, boolean useThumbnail) { super(); this.property = property; this.entityId = entityId; this.useThumbnail = useThumbnail; this.enabled = enabled; initWidget(uiBinder.createAndBindUi(this)); this.label.setText(localizedName); if (localizedName == null || "".equals(localizedName)) { labelHolder.addStyleName("app-clean-mg-right"); } setGridSize(size); thumbnail.addLoadHandler(new LoadHandler() { @Override public void onLoad(LoadEvent event) { thumbnailHolder.showWidget(0); buttonDownload.setEnabled(true); //Window.alert("ONLOAD:" + event.toDebugString()); } }); thumbnail.addErrorHandler(new ErrorHandler() { @Override public void onError(ErrorEvent event) { thumbnailHolder.showWidget(3); buttonDownload.setEnabled(false); } }); thumbnailHolder.add(new HTML(Aplikator.application.getConfigString("aplikator.binary.loading"))); thumbnailHolder.add(new HTML(Aplikator.application.getConfigString("aplikator.binary.uploaded"))); thumbnailHolder.add(new HTML(Aplikator.application.getConfigString("aplikator.binary.notAvailable"))); thumbnailHolder.showWidget(1); thumbnailHolder.getElement().getStyle().setProperty("width", "100%"); if (height > 0) { thumbnailHolder.getElement().getStyle().setHeight(height, Style.Unit.PX); } thumbnailHolder.getElement().getStyle().setDisplay(Style.Display.INLINE_BLOCK); LayoutUtils.addTooltip(buttonUpload, Aplikator.application.getConfigString("aplikator.binary.upload")); thumbnail.getElement().getStyle().setProperty("maxWidth", "100%"); thumbnail.getElement().getStyle().setProperty("maxHeight", "100%"); thumbnail.getElement().getStyle().clearWidth(); thumbnail.getElement().getStyle().clearHeight(); enableUpload(); LayoutUtils.addTooltip(buttonDownload, Aplikator.application.getConfigString("aplikator.binary.download")); buttonDownload.setEnabled(false); /*thumbnail.addDropHandler(new DropHandler() { @Override public void onDrop(DropEvent event) { event.preventDefault(); // not sure if the calculation is right, didn't test it really int x = (event.getNativeEvent().getClientX() - thumbnail.getAbsoluteLeft()) + Window.getScrollLeft(); int y = (event.getNativeEvent().getClientY() - thumbnail.getAbsoluteTop()) + Window.getScrollTop(); thumbnail.getElement().getStyle().clearBackgroundColor(); Window.alert("x: " + x + ", y:" + y); // add image with same URL as the dropped one to absolute panel at given coordinates //thumbnail.add(new Image(event.getData("text")), x, y); } });*/ wrapper.addDomHandler(new DragEnterHandler() { @Override public void onDragEnter(DragEnterEvent event) { } }, DragEnterEvent.getType()); wrapper.addDomHandler(new DragLeaveHandler() { @Override public void onDragLeave(DragLeaveEvent event) { highlight(false); } }, DragLeaveEvent.getType()); wrapper.addDomHandler(new DragOverHandler() { @Override public void onDragOver(DragOverEvent event) { highlight(true); } }, DragOverEvent.getType()); wrapper.addDomHandler(new DropHandler() { @Override public void onDrop(DropEvent event) { // stop default behaviour event.preventDefault(); event.stopPropagation(); // starts the fetching, reading and callbacks //handleFiles(event.getDataTransfer()); highlight(false); Window.alert("DROPPED" + event.getDataTransfer().getData("image/jpeg")); } }, DropEvent.getType()); } private void highlight(boolean on) { if (on) { wrapper.getElement().getStyle().setBorderWidth(10, Style.Unit.PX); } else { wrapper.getElement().getStyle().setBorderWidth(0, Style.Unit.PX); } } protected void setGridSize(int size) { wrapper.setSize(LayoutUtils.size(size)); } private Modal createDialogBox() { // Create a FormPanel and point it at a service. final Form form = new Form(); form.setAction(Aplikator.getBaseURL() + "upload"); // Because we're going to add a FileUpload widget, we'll need to set the // form to use the POST method, and multipart MIME encoding. form.setEncoding(FormPanel.ENCODING_MULTIPART); form.setMethod(FormPanel.METHOD_POST); FormElement.as(form.getElement()).setAcceptCharset("UTF-8"); // Create a panel to hold all of the form widgets. FieldSet panel = new FieldSet(); form.add(panel); // add hidden upload parameters FormControlStatic entityIdField = new FormControlStatic(); entityIdField.setId(ENTITY_ID); entityIdField.setText(this.entityId); entityIdField.setVisible(false); FormControlStatic propertyIdField = new FormControlStatic(); propertyIdField.setId(PROPERTY_ID); propertyIdField.setText(property.getId()); propertyIdField.setVisible(false); primaryKeyField = new FormControlStatic(); primaryKeyField.setId(PRIMARY_KEY_ID); primaryKeyField.setVisible(false); FormGroup entityIdFG = new FormGroup(); entityIdFG.add(entityIdField); FormGroup propertyIdFG = new FormGroup(); propertyIdFG.add(propertyIdField); FormGroup primaryKeyFG = new FormGroup(); primaryKeyFG.add(primaryKeyField); panel.add(entityIdFG); panel.add(propertyIdFG); panel.add(primaryKeyFG); // Create a FileUpload widget. upload = new OnChangeFileUpload(form); upload.setName("uploadFormElement"); panel.add(upload); panel.add(statusLabel); timer = new ProgressTimer(statusLabel); timer.scheduleRepeating(1000); final Modal db = new Modal(); db.getElement().getStyle().setOverflowY(Style.Overflow.AUTO);//fix against hidding scrollbar in modal stack ModalBody contents = new ModalBody(); db.setClosable(true); db.setSize(ModalSize.SMALL); db.setTitle(Aplikator.application.getConfigString("aplikator.binary.uploadTitle")); db.add(contents); db.setFade(true); contents.add(form); // Add an event handler to the form. form.addSubmitCompleteHandler(new AbstractForm.SubmitCompleteHandler() { @Override public void onSubmitComplete(AbstractForm.SubmitCompleteEvent event) { timer.setRunning(false); uploading = false; String uploadedFilename = ""; Document d = XMLParser.parse(event.getResults()); Node de = d.getDocumentElement(); if (de != null && de.getFirstChild() != null) { uploadedFilename = de.getFirstChild().getNodeValue(); } if ("".equals(uploadedFilename)) { statusLabel.setHTML(Aplikator.application.getConfigString("aplikator.binary.statusUploadFailed")); } else if (uploadedFilename.startsWith(ERROR_PREFIX)) { statusLabel.setHTML(Aplikator.application.getConfigString("aplikator.binary.statusUploadFailed") + ": " + uploadedFilename.replace(ERROR_PREFIX, "")); } else { statusLabel.setHTML(Aplikator.application.getConfigString("aplikator.binary.statusUploaded")); setValue(uploadedFilename); setDirty(true); thumbnailHolder.showWidget(2); //Window.alert("COMPLETE"); new Timer() { public void run() { db.hide(); } }.schedule(1500); } } }); form.addSubmitHandler(new AbstractForm.SubmitHandler() { @Override public void onSubmit(AbstractForm.SubmitEvent event) { uploading = true; timer.setRunning(true); // start the timer that monitors the progress new Timer() { public void run() { if (uploading) { timer.run(); } } }.schedule(2000); primaryKeyField.setText(Integer.toString(primaryKey.getId())); statusLabel.setText(Aplikator.application.getConfigString("aplikator.binary.statusStarted")); //Window.alert("SUBMITTED"); } }); return db; } @UiHandler("buttonUpload") void buttonUploadClicked(ClickEvent e) { if (uploadDialog == null) { uploadDialog = createDialogBox(); } resetUpload(); uploadDialog.show(); } private void resetUpload() { statusLabel.setText(""); timer.reset(); upload.getElement().setPropertyString("value", ""); } @UiHandler("buttonDownload") void buttonDownloadClicked(ClickEvent e) { Window.open(getDownloadUrl(FULL_SIZE_ATTACHMENT_CODE), "_self", ""); } public void setPrimaryKey(PrimaryKey primaryKey) { this.primaryKey = primaryKey; this.tempFileId = null; enableUpload(); buttonDownload.setEnabled(false); thumbnailHolder.showWidget(1); if (primaryKey.getId() > 0) { thumbnail.setUrl(getDownloadUrl(useThumbnail ? THUMBNAIL_SIZE_CODE : PREVIEW_SIZE_CODE)); buttonDownload.setHref(getDownloadUrl(FULL_SIZE_ATTACHMENT_CODE)); } else { thumbnailHolder.showWidget(3); } } private String getDownloadUrl(int maxSize) { StringBuilder url = new StringBuilder(Aplikator.getBaseURL() + "download?"); url.append(ENTITY_ID + "=" + entityId + "&"); url.append(PROPERTY_ID + "=" + property.getId() + "&"); url.append(PRIMARY_KEY_ID + "=" + primaryKey.getId() + "&"); url.append(MAXSIZE_ID + "=" + maxSize + "&"); url.append("timestamp" + "=" + (new Date()).getTime()); return url.toString(); } private void enableUpload() { buttonUpload.setEnabled(enabled); } @UiHandler("thumbnail") void showLargePreview(ClickEvent e) { final Modal dialogBox = new Modal(); dialogBox.getElement().getStyle().setOverflowY(Style.Overflow.AUTO);//fix against hidding scrollbar in modal stack dialogBox.setSize(ModalSize.LARGE); //dialogBox.setDataBackdrop(ModalBackdrop.STATIC); dialogBox.setRemoveOnHide(true); ModalBody contents = new ModalBody(); Image image = new Image(getDownloadUrl(PREVIEW_SIZE_CODE)); image.addClickHandler(new ClickHandler() { public void onClick(ClickEvent event) { dialogBox.hide(); } }); ScrollPanel imageScroller = new ScrollPanel(image); dialogBox.add(contents); contents.add(imageScroller); dialogBox.setFade(true); dialogBox.show(); } @Override public PropertyDTO getProperty() { return property; } @Override public String getValue() { return tempFileId; } @Override public void setValue(String value) { tempFileId = value; ValueChangeEvent.fire(this, value); } @Override public boolean isDirty() { return dirty; } @Override public void setDirty(boolean dirty) { this.dirty = dirty; } @Override public void setEnabled(boolean enabled) { if (property.getRefferedThrough() != null) { enabled = false; } this.enabled = enabled; enableUpload(); } @Override public void grabFocus() { } @Override public void addEnterHandler(Command command) { } @Override public HandlerRegistration addValueChangeHandler(ValueChangeHandler<String> handler) { return this.addHandler(handler, ValueChangeEvent.getType()); } interface BinaryFieldWidgetUiBinder extends UiBinder<Column, BinaryFieldWidget> { } } class OnChangeFileUpload extends FileUpload { private Form form; public OnChangeFileUpload(Form form) { super(); this.form = form; sinkEvents(Event.ONCHANGE); } public void onBrowserEvent(Event event) { super.onBrowserEvent(event); if (DOM.eventGetType(event) == Event.ONCHANGE) { //Window.alert("BEFORE SUBMIT"); form.submit(); } } }